package com.zl.protocol;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author chenzy
 * @since 2022-11-10
 **/
public class ByteUtil {
    public static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',};

    public static byte random() {
        return (byte) (Math.random() * 256);
    }

    public static List<Byte> list(byte... bytes) {
        if (bytes == null) {
            return List.of();
        }
        var list = new ArrayList<Byte>(bytes.length);
        for (var b : bytes) {
            list.add(b);
        }
        return list;
    }

    /*字节集合转二进制的int数组*/
    public static int[] byteList2BinaryArray(List<Byte> bList) {
        var size = bList.size();
        var result = new int[size * 8];
        for (var i = 0; i < size; i++) {
            System.arraycopy(byte2BinaryArray(bList.get(i)), 0, result, i * 8, 8);
        }
        return result;
    }

    /*字节数组转二进制的int数组*/
    public static int[] byteArray2BinaryArray(byte... bList) {
        var result = new int[bList.length * 8];
        for (var i = 0; i < bList.length; i++) {
            System.arraycopy(byte2BinaryArray(bList[i]), 0, result, i * 8, 8);
        }
        return result;
    }

    /*字节->二进制的int数组*/
    public static int[] byte2BinaryArray(byte val) {
//        var temp=b& 0xFF;/*使用>>>无符号右移就不需要&0xFF,使用>>就需要&0xFF*/
        var result = new int[8];
        for (int i = 7; i >= 0; i--) {
            result[i] = val & 1;
            val = (byte) (val >>> 1);/*>>>无符号右移*/
        }
        return result;
    }

    /*字节集合->十六进制字符串*/
    @Deprecated
    private static String byteList2HexFq(List<Byte> bytes) {
        var result = new StringBuffer();
        byte mv = (byte) (0xff >> 4);
        bytes.forEach(b -> {
            var temp = b & 0xFF;
            result.append(hexDigits[temp >>> 4]).append(hexDigits[temp & mv]);
        });
        return result.toString();
    }

    /*字节数据转成十六进制字符串*/
    public static String byte2Hex(byte data) {
        var result = Integer.toHexString(data & 0xFF).toUpperCase();
        return result.length() == 2 ? result : "0".concat(result);
    }

    /*字节集合->十六进制字符串*/
    public static String byteList2Hex(List<Byte> bytes) {
        return bytes.stream().map(ByteUtil::byte2Hex).collect(Collectors.joining());
    }

    /*字节数组->十六进制字符串*/
    public static String byteArray2Hex(byte[] bytes) {
        var result = new StringBuilder();
        for (var b : bytes) {
            result.append(ByteUtil.byte2Hex(b));
        }
        return result.toString();
    }

    /*二进制int数组->字节*/
    public static Byte binaryArray2Byte(int[] source) {
        if (source.length != 8) {
            throw new RuntimeException("二进制数组长度不为8位");
        }
        byte result = (byte) source[7];
        for (int i = 6, j = 1; i >= 0; i--, j++) {
            if (source[i] == 1) {
                result += (1 << j);
            }
        }
        return result;
    }

    /*二进制int数组->字节集合*/
    public static List<Byte> binaryArray2ByteList(int[] source) {
        var l = source.length;
        if (l % 8 != 0) {
            throw new RuntimeException("二进制数组长度不为8的倍数");
        }
        var result = new ArrayList<Byte>(l / 8);
        for (var i = 0; i < l; i += 8) {
            result.add(binaryArray2Byte(Arrays.copyOfRange(source, i, i + 8)));
        }
        return result;
    }

    /*二进制int数组->十六进制字符串*/
    public static String binaryArray2Hex(int[] source) {
        var l = source.length;
        if (l % 8 != 0) {
            throw new RuntimeException("二进制数组长度不为8的倍数");
        }
        var result = new StringBuilder();
        for (var i = 0; i < l; i += 8) {
            result.append(NumberUtil.byte2Hex(binaryArray2Byte(Arrays.copyOfRange(source, i, i + 8))));
        }
        return result.toString();
    }

    /*十六进制字符串->字节集合:最佳实践*/
    public static List<Byte> hex2ByteList(String hex) {
        var chars = hex.toCharArray();
        var l = chars.length;
        var result = new ArrayList<Byte>(chars.length / 2);
        for (int i = 0; i < l; i += 2) {
            result.add((byte) ((Character.digit(chars[i], 16) << 4) + Character.digit(chars[i + 1], 16)));
        }
        return result;
    }

    /*十六进制字符串->字节数组:最佳实践*/
    public static byte[] hex2ByteArray(String hex) {
        var chars = hex.toCharArray();
        var l = chars.length;
        var result = new byte[chars.length / 2];
        for (int i = 0, j = 0; i < l; i += 2, j++) {
            result[j] = (byte) ((Character.digit(chars[i], 16) << 4) + Character.digit(chars[i + 1], 16));
        }
        return result;
    }

    /*十六进制字符串->字节数组:最佳实践*/
    public static Byte[] hex2ByteArray2(String hex) {
        var chars = hex.toCharArray();
        var l = chars.length;
        var result = new Byte[chars.length / 2];
        for (int i = 0, j = 0; i < l; i += 2, j++) {
            result[j] = (byte) ((Character.digit(chars[i], 16) << 4) + Character.digit(chars[i + 1], 16));
        }
        return result;
    }

    public static byte[] int2ByteArray(int value, int len) {
        var b = new byte[len];
        for (int i = 0; i < len; i++) {
            b[len - i - 1] = (byte) ((value >> 8 * i) & 0xff);
        }
        return b;
    }

    public static Byte[] int2ByteArray2(int value, int len) {
        var b = new Byte[len];
        for (int i = 0; i < len; i++) {
            b[len - i - 1] = (byte) ((value >> 8 * i) & 0xff);
        }
        return b;
    }

    public static byte[] long2ByteArray(long value, int len) {
        var b = new byte[len];
        for (int i = 0; i < len; i++) {
            b[len - i - 1] = (byte) ((value >> 8 * i) & 0xff);
        }
        return b;
    }

    public static Byte[] long2ByteArray2(long value, int len) {
        var b = new Byte[len];
        for (int i = 0; i < len; i++) {
            b[len - i - 1] = (byte) ((value >> 8 * i) & 0xff);
        }
        return b;
    }

    public static List<Byte> long2ByteList(long value, int len) {
        List<Byte> result = new ArrayList(len);
        for (int i = len - 1; i >= 0; --i) {
            result.add((byte) (value >> 8 * i & 255));
        }
        return result;
    }

    public static int byteList2Int(List<Byte> data) {
        var result = 0;
        var len = data.size();
        if (len > 3) {
            return -1;
        }
        for (int i = 0; i < len; i++) {
            result += ((data.get(i) & 255) << (8 * (len - i - 1)));
        }
        return result;
    }

    public static Long byteList2Long(List<Byte> data) {
        var result = 0L;
        var len = data.size();
        for (int i = 0; i < len; i++) {
            result += (long) (data.get(i) & 255) << (8 * (len - i - 1));
        }
        return result;
    }

    /**
     * @param data 待转换的字节
     * @param desc true：低位在前，false:高位在前
     * @return 结果
     */
    public static Long byteList2Long(List<Byte> data, boolean desc) {
        var result = 0L;
        var len = data.size();
        for (int i = 0; i < len; i++) {
            result += (long) (data.get(i) & 255) << 8 * (desc ? i : (len - i - 1));
        }
        return result;
    }

    public static Long byteArray2Long(Byte... data) {
        var result = 0L;
        var len = data.length;
        for (int i = 0; i < len; i++) {
            result += (long) (data[i] & 255) << (8 * (len - i - 1));
        }
        return result;
    }

    public static List<Byte> int2ByteList(int value, int len) {
        List<Byte> result = new ArrayList(len);
        for (int i = len - 1; i >= 0; --i) {
            result.add((byte) (value >> 8 * i & 255));
        }
        return result;
    }

    public static String list2HexFillPrefix(List<Byte> bytes, int len, String spilt, byte fill) {
        while (bytes.size() < len) {
            bytes.add(0, fill);
        }
        return bytes.stream().map(item -> byte2Hex(item)).collect(Collectors.joining(spilt));
    }

    public static String int2Hex(int value, int len, String spilt) {
        var result = new StringBuilder(byte2Hex((byte) (value >> 8 * (len - 1) & 255)));
        for (int i = len - 2; i >= 0; --i) {
            result.append(spilt).append(byte2Hex((byte) (value >> 8 * i & 255)));
        }
        return result.toString();
    }

    public static String long2Hex(long value, int len) {
        var result = new StringBuilder(byte2Hex((byte) (value >> 8 * (len - 1) & 255)));
        for (int i = len - 2; i >= 0; --i) {
            result.append(byte2Hex((byte) (value >> 8 * i & 255)));
        }
        return result.toString();
    }
}
